﻿using System.Diagnostics.CodeAnalysis;

namespace TUnit.Assertions.Tests.Assertions.Delegates;

public partial class Throws
{
    public class ExceptionTests
    {
        [Test]
        public async Task Fails_For_Code_Without_Exceptions()
        {
            var expectedMessage = """
                                  Expected to throw Exception
                                  but no exception was thrown

                                  at Assert.That(action).ThrowsException()
                                  """.NormalizeLineEndings();
            var action = () => { };

            var sut = async ()
                => await Assert.That(action).ThrowsException();

            var thrownException = await Assert.That(sut).ThrowsException();
            await Assert.That(thrownException.Message.NormalizeLineEndings()).IsEqualTo(expectedMessage);
        }

        [Test]
        [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application assemblies.", Justification = "Test method.")]
        public async Task Returns_Exception_When_Awaited()
        {
            Exception exception = CreateCustomException();
            Action action = () => throw exception;

            var result = await Assert.That(action).ThrowsException();

            await Assert.That(result).IsSameReferenceAs(exception);
        }

        [Test]
        public async Task Succeeds_For_Code_With_Exceptions()
        {
            Exception exception = CreateCustomException();
            Action action = () => throw exception;

            var sut = async ()
                => await Assert.That(action).ThrowsException();

            await Assert.That(sut).ThrowsNothing();
        }

        private void ThrowsArgumentException()
            => throw new ArgumentException("Just for testing");

        [Test]
        public async Task ThrowsAsync_DoesNotCheckType()
        {
            await Assert.That(async () =>
                await Assert.ThrowsAsync<OverflowException>(LocalTestFunction)
            ).Throws<AssertionException>();
            return;

            Task LocalTestFunction()
            {
                ThrowsArgumentException();
                return Task.CompletedTask;
            }
        }
    }
}
